#include "HP_TcpClient.h"

static BOOL luaL_optboolean(lua_State* L, int arg, BOOL def) {
	if (lua_isnoneornil(L, arg)) {
		return def;
	}
	return lua_toboolean(L, arg);
}

static ITcpClient* GetTcpClient(lua_State* L) {
	lua_getuservalue(L, 1);
	ITcpClient* p = (ITcpClient*)lua_topointer(L, -1);
	lua_pop(L, 1);
	return p;
}

int SendSmallFile(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	lua_pushboolean(L, cli->SendSmallFile(luaL_checkstring(L, 2),
		(LPWSABUF)luaL_optlstring(L, 3, nullptr, NULL),
		(LPWSABUF)luaL_optlstring(L, 4, nullptr, NULL)));
	return 1;
}

int SetSocketBufferSize(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	cli->SetSocketBufferSize((DWORD)luaL_checkinteger(L, 2));
	return 0;
}

int SetKeepAliveTime(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	cli->SetKeepAliveTime((DWORD)luaL_checkinteger(L, 2));
	return 0;
}

int SetKeepAliveInterval(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	cli->SetKeepAliveInterval((DWORD)luaL_checkinteger(L, 2));
	return 0;
}

int GetSocketBufferSize(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	lua_pushinteger(L, cli->GetSocketBufferSize());
	return 1;
}

int GetKeepAliveTime(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	lua_pushinteger(L, cli->GetKeepAliveTime());
	return 1;
}

int GetKeepAliveInterval(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	lua_pushinteger(L, cli->GetKeepAliveInterval());
	return 1;
}
//IClient
int Start(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	BOOL r = cli->Start(luaL_checkstring(L, 2), (USHORT)luaL_checkinteger(L, 3), luaL_optboolean(L, 4, FALSE),
		luaL_optstring(L, 5, nullptr), (USHORT)luaL_optinteger(L, 6, 0U));
	lua_pushboolean(L, r);
	return 1;
}

int Stop(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	HP_mutex* mutex = *(HP_mutex**)lua_getextraspace(L);
	HP_UnlockMutex(mutex);
	BOOL r = cli->Stop();
	HP_LockMutex(mutex);
	lua_pushboolean(L, r);
	return 1;
}

int Send(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	size_t len;
	BYTE* buf = (BYTE*)luaL_checklstring(L, 2, &len);
	lua_pushboolean(L, cli->Send(buf, (int)len, (int)luaL_optinteger(L, 3, 0)));
	return 1;
}
//int SendPackets(lua_State* L){
//	ITcpClient* cli = GetTcpClient(L);
//
//	return 0;
//}
int PauseReceive(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	lua_pushboolean(L, cli->PauseReceive());
	return 1;
}

int Wait(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	lua_pushboolean(L, cli->Wait((DWORD)luaL_optinteger(L, 2, INFINITE)));
	return 1;
}
//int SetExtra(lua_State* L){
//	ITcpClient* cli = GetTcpClient(L);
//
//	return 0;
//}
//int GetExtra(lua_State* L){
//	ITcpClient* cli = GetTcpClient(L);
//
//	return 0;
//}
int IsSecure(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	lua_pushboolean(L, cli->IsSecure());
	return 1;
}

int HasStarted(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	lua_pushboolean(L, cli->HasStarted());
	return 1;
}

int GetState(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	switch (cli->GetState()) {
		CASE(SS_STARTING)
			CASE(SS_STARTED)
			CASE(SS_STOPPING)
			CASE(SS_STOPPED)
	}
	return 1;
}

int GetLastError(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	switch (cli->GetLastError()) {
		CASE(SE_OK)
		CASE(SE_ILLEGAL_STATE)
		CASE(SE_INVALID_PARAM)
		CASE(SE_SOCKET_CREATE)
		CASE(SE_SOCKET_BIND)
		CASE(SE_SOCKET_PREPARE)
		CASE(SE_SOCKET_LISTEN)
		CASE(SE_CP_CREATE)
		CASE(SE_WORKER_THREAD_CREATE)
		CASE(SE_DETECT_THREAD_CREATE)
		CASE(SE_SOCKE_ATTACH_TO_CP)
		CASE(SE_CONNECT_SERVER)
		CASE(SE_NETWORK)
		CASE(SE_DATA_PROC)
		CASE(SE_DATA_SEND)
		CASE(SE_SSL_ENV_NOT_READY)
	}
	return 1;
}

int GetLastErrorDesc(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	lua_pushstring(L, cli->GetLastErrorDesc());
	return 1;
}

int GetConnectionID(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	lua_pushinteger(L, cli->GetConnectionID());
	return 1;
}

int GetLocalAddress(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	luaL_Buffer b;
	char* p = luaL_buffinitsize(L, &b, LUAL_BUFFERSIZE);
	int len = LUAL_BUFFERSIZE;
	USHORT port;
	if (cli->GetLocalAddress(p, len, port)) {
		luaL_pushresultsize(&b, len - 1);
		lua_pushinteger(L, port);
		return 2;
	}
	return 0;
}

int GetRemoteHost(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	luaL_Buffer b;
	char* p = luaL_buffinitsize(L, &b, LUAL_BUFFERSIZE);
	int len = LUAL_BUFFERSIZE;
	USHORT port;
	if (cli->GetRemoteHost(p, len, port)) {
		luaL_pushresultsize(&b, len - 1);
		lua_pushinteger(L, port);
		return 2;
	}
	return 0;
}

int GetPendingDataLength(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	int v;
	cli->GetPendingDataLength(v);
	lua_pushinteger(L, v);
	return 1;
}

int IsPauseReceive(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	BOOL v;
	cli->IsPauseReceive(v);
	lua_pushboolean(L, v);
	return 1;
}

int IsConnected(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	lua_pushboolean(L, cli->IsConnected());
	return 1;
}

int SetReuseAddressPolicy(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	static const char* const opts[] = { "RAP_NONE", "RAP_ADDR_ONLY", "RAP_ADDR_AND_PORT", NULL };
	//static const int optsnum[] = {RAP_NONE, RAP_ADDR_ONLY, RAP_ADDR_AND_PORT,};
	cli->SetReuseAddressPolicy(EnReuseAddressPolicy(luaL_checkoption(L, 2, "RAP_NONE", opts)));
	return 0;
}

int SetFreeBufferPoolSize(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	cli->SetFreeBufferPoolSize((DWORD)luaL_checkinteger(L, 2));
	return 0;
}

int SetFreeBufferPoolHold(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	cli->SetFreeBufferPoolHold((DWORD)luaL_checkinteger(L, 2));
	return 0;
}

int GetReuseAddressPolicy(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	switch (cli->GetReuseAddressPolicy()) {
		CASE(RAP_NONE)
			CASE(RAP_ADDR_ONLY)
			CASE(RAP_ADDR_AND_PORT)
	}
	return 1;
}

int GetFreeBufferPoolSize(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	lua_pushinteger(L, cli->GetFreeBufferPoolSize());
	return 1;
}

int GetFreeBufferPoolHold(lua_State* L) {
	ITcpClient* cli = GetTcpClient(L);
	lua_pushinteger(L, cli->GetFreeBufferPoolHold());
	return 1;
}
